package com.pokermind.dse.tcp.protocol;

import com.fasterxml.jackson.databind.JsonNode;
import io.netty.channel.Channel;

import java.util.concurrent.atomic.AtomicLong;

/**
 * TCP Protocol Message Wrapper
 * TCP协议消息封装类，支持JSON序列化
 * 
 * Protocol Format:
 * +----------+----------+------------------+
 * | Protocol | Body     | JSON String      |
 * | ID       | Length   |                  |
 * | (2 bytes)| (4 bytes)| (N bytes)        |
 * +----------+----------+------------------+
 * 
 * 设计要点:
 * 1. 轻量级对象，支持对象池化
 * 2. 包含请求追踪信息，支持链路追踪
 * 3. 线程安全的请求ID生成
 * 4. 支持JSON序列化/反序列化
 * 
 * @author PokerMind Team
 */
public class ProtocolMessage {

    // 全局请求ID生成器
    private static final AtomicLong REQUEST_ID_GENERATOR = new AtomicLong(0);

    // 协议头信息
    private final short protocolId;
    private final int bodyLength;
    private final long requestId;
    
    // 消息体 (JSON)
    private final String jsonBody;
    private final JsonNode jsonNode;  // 解析后的JSON节点，用于快速访问
    
    // 元数据
    private final Channel channel;
    private final long timestamp;
    private volatile long processStartTime;
    private volatile long processEndTime;

    /**
     * 构造请求消息
     */
    public ProtocolMessage(short protocolId, String jsonBody, Channel channel) {
        this.protocolId = protocolId;
        this.jsonBody = jsonBody;
        this.bodyLength = jsonBody.getBytes().length;
        this.channel = channel;
        this.requestId = REQUEST_ID_GENERATOR.incrementAndGet();
        this.timestamp = System.currentTimeMillis();
        this.jsonNode = null; // 延迟解析
    }

    /**
     * 构造请求消息（带解析的JSON节点）
     */
    public ProtocolMessage(short protocolId, String jsonBody, JsonNode jsonNode, Channel channel) {
        this.protocolId = protocolId;
        this.jsonBody = jsonBody;
        this.jsonNode = jsonNode;
        this.bodyLength = jsonBody.getBytes().length;
        this.channel = channel;
        this.requestId = REQUEST_ID_GENERATOR.incrementAndGet();
        this.timestamp = System.currentTimeMillis();
    }

    /**
     * 构造响应消息（复用请求ID）
     */
    public ProtocolMessage(short protocolId, String jsonBody, Channel channel, long requestId) {
        this.protocolId = protocolId;
        this.jsonBody = jsonBody;
        this.bodyLength = jsonBody.getBytes().length;
        this.channel = channel;
        this.requestId = requestId;
        this.timestamp = System.currentTimeMillis();
        this.jsonNode = null;
    }

    // ===============================================
    // Getters
    // ===============================================

    public short getProtocolId() {
        return protocolId;
    }

    public int getBodyLength() {
        return bodyLength;
    }

    public long getRequestId() {
        return requestId;
    }

    public String getJsonBody() {
        return jsonBody;
    }

    public JsonNode getJsonNode() {
        return jsonNode;
    }

    public Channel getChannel() {
        return channel;
    }

    public long getTimestamp() {
        return timestamp;
    }

    // ===============================================
    // Performance Tracking
    // ===============================================

    public void markProcessStart() {
        this.processStartTime = System.nanoTime();
    }

    public void markProcessEnd() {
        this.processEndTime = System.nanoTime();
    }

    public long getProcessDurationNanos() {
        if (processStartTime == 0 || processEndTime == 0) {
            return 0;
        }
        return processEndTime - processStartTime;
    }

    public double getProcessDurationMillis() {
        return getProcessDurationNanos() / 1_000_000.0;
    }

    // ===============================================
    // Utility Methods
    // ===============================================

    public String getProtocolName() {
        return ProtocolConstants.getProtocolName(protocolId);
    }

    public String getProtocolType() {
        return ProtocolConstants.getProtocolType(protocolId);
    }

    public boolean isRequest() {
        return ProtocolConstants.isRequest(protocolId);
    }

    public boolean isResponse() {
        return ProtocolConstants.isResponse(protocolId);
    }

    public short getResponseProtocolId() {
        return ProtocolConstants.getResponseProtocol(protocolId);
    }

    /**
     * 检查消息是否来自有效的连接
     */
    public boolean isChannelActive() {
        return channel != null && channel.isActive();
    }

    /**
     * 获取客户端标识（用于日志和监控）
     */
    public String getClientId() {
        if (channel == null) {
            return "unknown";
        }
        return channel.remoteAddress().toString();
    }

    /**
     * 获取消息大小（用于监控）
     */
    public int getMessageSize() {
        return ProtocolConstants.HEADER_SIZE + bodyLength;
    }

    // ===============================================
    // Factory Methods
    // ===============================================

    /**
     * 创建请求消息
     */
    public static ProtocolMessage createRequest(short protocolId, String jsonBody, Channel channel) {
        return new ProtocolMessage(protocolId, jsonBody, channel);
    }

    /**
     * 创建请求消息（带解析的JSON节点）
     */
    public static ProtocolMessage createRequest(short protocolId, String jsonBody, JsonNode jsonNode, Channel channel) {
        return new ProtocolMessage(protocolId, jsonBody, jsonNode, channel);
    }

    /**
     * 创建响应消息
     */
    public static ProtocolMessage createResponse(ProtocolMessage request, String jsonBody) {
        short responseProtocolId = request.getResponseProtocolId();
        return new ProtocolMessage(responseProtocolId, jsonBody, request.getChannel(), request.getRequestId());
    }

    /**
     * 创建错误响应消息 - 使用新的标准格式
     */
    public static ProtocolMessage createErrorResponse(ProtocolMessage request, int errorCode, String errorMessage) {
        // 提取客户端请求ID（如果有的话）
        String clientRequestId = extractClientRequestId(request);
        if (clientRequestId == null) {
            clientRequestId = String.valueOf(request.getRequestId()); // 兜底使用服务端请求ID转字符串
        }
        
        String errorJson = String.format(
            "{\"rqid\":\"%s\",\"code\":%d,\"desc\":\"%s\",\"data\":null}", 
            clientRequestId, errorCode, errorMessage
        );
        return new ProtocolMessage(ProtocolConstants.ERROR_RESP, errorJson, request.getChannel(), request.getRequestId());
    }

    /**
     * 创建业务错误响应消息 - 使用新的标准格式
     */
    public static ProtocolMessage createBusinessErrorResponse(ProtocolMessage request, String errorMessage, String details) {
        // 提取客户端请求ID（如果有的话）
        String clientRequestId = extractClientRequestId(request);
        if (clientRequestId == null) {
            clientRequestId = String.valueOf(request.getRequestId()); // 兜底使用服务端请求ID转字符串
        }
        
        String errorJson = String.format(
            "{\"rqid\":\"%s\",\"code\":4000,\"desc\":\"%s\",\"data\":{\"error\":\"%s\",\"detail\":\"%s\"}}", 
            clientRequestId, errorMessage, errorMessage, details
        );
        return new ProtocolMessage(ProtocolConstants.BUSINESS_ERROR_RESP, errorJson, request.getChannel(), request.getRequestId());
    }
    
    /**
     * 从请求中提取客户端请求ID
     */
    private static String extractClientRequestId(ProtocolMessage request) {
        try {
            if (request.getJsonNode() != null && request.getJsonNode().has("rqid")) {
                return request.getJsonNode().get("rqid").asText();
            } else if (request.getJsonBody() != null) {
                com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                com.fasterxml.jackson.databind.JsonNode jsonNode = mapper.readTree(request.getJsonBody());
                if (jsonNode.has("rqid")) {
                    return jsonNode.get("rqid").asText();
                }
            }
        } catch (Exception e) {
            // 忽略解析错误，返回null
        }
        return null;
    }

    // ===============================================
    // toString for debugging
    // ===============================================

    @Override
    public String toString() {
        return String.format(
            "ProtocolMessage{protocolId=%d(%s), type=%s, bodyLength=%d, requestId=%d, clientId='%s', timestamp=%d, processDuration=%.2fms}",
            protocolId, getProtocolName(), getProtocolType(), bodyLength, requestId, getClientId(), timestamp, getProcessDurationMillis()
        );
    }

    /**
     * 获取详细信息（包含JSON内容，用于调试）
     */
    public String toDetailString() {
        return String.format(
            "%s, jsonBody='%s'", 
            toString(), 
            jsonBody.length() > 200 ? jsonBody.substring(0, 200) + "..." : jsonBody
        );
    }
}
